{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "true"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "### pry-docの読み込み\n",
    "#require \"/root/jupyter/vendor/bundle/ruby/2.3.0/gems/pry-doc-0.10.0/lib/pry-doc\"\n",
    "#require \"/root/git_jupyter_notebook/Ruby/vendor/bundle/ruby/2.3.0/gems/pry-doc-0.10.0/lib/pry-doc\"\n",
    "require \"/Users/ftakao2007/jupyter/vendor/bundle/ruby/2.3.0/gems/pry-doc-0.10.0/lib/pry-doc\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "# Procクラス\n",
    "\n",
    "* Procクラス\n",
    "    * ブロックを実行時のローカル変数のスコープなどのコンテキストと共にオブジェクト化した手続きオブジェクトを扱うクラス\n",
    "    * 名前のない関数(無名関数)のように使うことができます\n",
    "    * 手続きを実行するにはcallメソッドを使う\n",
    "    * 引数をとることができる\n",
    "        * 生成された手続きオブジェクトの引数の数はarityメソッドで取得できる"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "#<Proc:0x007fefd4c1aa18@(pry):26>\n",
      "OK\n",
      "\n",
      "0\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "0"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "puts f = Proc.new{ puts 'OK'}\n",
    "puts f.call"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "#<Proc:0x007fefd4c84a58@(pry):41>\n",
      "2\n",
      "OK\n",
      "NG\n",
      "\n"
     ]
    }
   ],
   "source": [
    "puts f = Proc.new{ |s,t| puts s,t}\n",
    "puts f.arity\n",
    "\n",
    "puts f.call('OK','NG')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\u001b[1mFrom:\u001b[0m proc.c (C Method):\n",
      "\u001b[1mOwner:\u001b[0m Proc\n",
      "\u001b[1mVisibility:\u001b[0m public\n",
      "\u001b[1mSignature:\u001b[0m arity()\n",
      "\u001b[1mNumber of lines:\u001b[0m 35\n",
      "\n",
      "Returns the number of mandatory arguments. If the block\n",
      "is declared to take no arguments, returns 0. If the block is known\n",
      "to take exactly n arguments, returns n.\n",
      "If the block has optional arguments, returns -n-1, where n is the\n",
      "number of mandatory arguments, with the exception for blocks that\n",
      "are not lambdas and have only a finite number of optional arguments;\n",
      "in this latter case, returns n.\n",
      "Keywords arguments will considered as a single additional argument,\n",
      "that argument being mandatory if any keyword argument is mandatory.\n",
      "A proc with no argument declarations\n",
      "is the same as a block declaring || as its arguments.\n",
      "\n",
      "   proc {}.arity                  \u001b[1;34m#=>  0\u001b[0m\n",
      "   proc { || }.arity              \u001b[1;34m#=>  0\u001b[0m\n",
      "   proc { |a| }.arity             \u001b[1;34m#=>  1\u001b[0m\n",
      "   proc { |a, b| }.arity          \u001b[1;34m#=>  2\u001b[0m\n",
      "   proc { |a, b, c| }.arity       \u001b[1;34m#=>  3\u001b[0m\n",
      "   proc { |*a| }.arity            \u001b[1;34m#=> -1\u001b[0m\n",
      "   proc { |a, *b| }.arity         \u001b[1;34m#=> -2\u001b[0m\n",
      "   proc { |a, *b, c| }.arity      \u001b[1;34m#=> -3\u001b[0m\n",
      "   proc { |\u001b[35mx\u001b[0m:, \u001b[35my\u001b[0m:, \u001b[35mz\u001b[0m:\u001b[1;34m0\u001b[0m| }.arity   \u001b[1;34m#=>  1\u001b[0m\n",
      "   proc { |*a, \u001b[35mx\u001b[0m:, \u001b[35my\u001b[0m:\u001b[1;34m0\u001b[0m| }.arity   \u001b[1;34m#=> -2\u001b[0m\n",
      "\n",
      "   proc   { |x=\u001b[1;34m0\u001b[0m| }.arity         \u001b[1;34m#=>  0\u001b[0m\n",
      "   lambda { |x=\u001b[1;34m0\u001b[0m| }.arity         \u001b[1;34m#=> -1\u001b[0m\n",
      "   proc   { |x=\u001b[1;34m0\u001b[0m, y| }.arity      \u001b[1;34m#=>  1\u001b[0m\n",
      "   lambda { |x=\u001b[1;34m0\u001b[0m, y| }.arity      \u001b[1;34m#=> -2\u001b[0m\n",
      "   proc   { |x=\u001b[1;34m0\u001b[0m, y=\u001b[1;34m0\u001b[0m| }.arity    \u001b[1;34m#=>  0\u001b[0m\n",
      "   lambda { |x=\u001b[1;34m0\u001b[0m, y=\u001b[1;34m0\u001b[0m| }.arity    \u001b[1;34m#=> -1\u001b[0m\n",
      "   proc   { |x, y=\u001b[1;34m0\u001b[0m| }.arity      \u001b[1;34m#=>  1\u001b[0m\n",
      "   lambda { |x, y=\u001b[1;34m0\u001b[0m| }.arity      \u001b[1;34m#=> -2\u001b[0m\n",
      "   proc   { |(x, y), z=\u001b[1;34m0\u001b[0m| }.arity \u001b[1;34m#=>  1\u001b[0m\n",
      "   lambda { |(x, y), z=\u001b[1;34m0\u001b[0m| }.arity \u001b[1;34m#=> -2\u001b[0m\n",
      "   proc   { |a, \u001b[35mx\u001b[0m:\u001b[1;34m0\u001b[0m, \u001b[35my\u001b[0m:\u001b[1;34m0\u001b[0m| }.arity \u001b[1;34m#=>  1\u001b[0m\n",
      "   lambda { |a, \u001b[35mx\u001b[0m:\u001b[1;34m0\u001b[0m, \u001b[35my\u001b[0m:\u001b[1;34m0\u001b[0m| }.arity \u001b[1;34m#=> -2\u001b[0m\n"
     ]
    }
   ],
   "source": [
    "show-doc Proc#arity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2\n",
      "2\n",
      "\n",
      "-2\n",
      "-2\n",
      "\n",
      "可変長引数を受け付ける場合、負の整数-(必要とされる引数の数 + 1)\n",
      "1\n",
      "-2\n",
      "\n"
     ]
    }
   ],
   "source": [
    "puts proc{|x, y|}.arity\n",
    "puts lambda{|x, y|}.arity\n",
    "puts\n",
    "\n",
    "puts proc{|x, *y|}.arity\n",
    "puts lambda{|x, *y|}.arity\n",
    "puts\n",
    "    \n",
    "puts \"可変長引数を受け付ける場合、負の整数-(必要とされる引数の数 + 1)\"\n",
    "puts proc{|x=10, y|}.arity\n",
    "puts lambda{|x=10, y|}.arity\n",
    "puts"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "6"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "proc1 = proc{|x=10, y| x + y}\n",
    "lmd1 = lambda{|x=10, y| x + y}\n",
    "  \n",
    "def func(z)\n",
    "  z + yield\n",
    "end\n",
    "\n",
    "func(1){|x=2, y| y=3; x + y}\n",
    "\n",
    "# def func_a x, &proc1\n",
    "#   x + proc1.call\n",
    "# end\n",
    "# puts func_a(1){ 2 }\n",
    "# puts\n",
    "\n",
    "# def func_b y\n",
    "#   y + yield\n",
    "# end\n",
    "# puts func_b(3){ 4 }\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "引数無し\n",
      "6\n",
      "0\n",
      "\n",
      "引数有り\n",
      "6\n",
      "1\n"
     ]
    }
   ],
   "source": [
    "puts \"引数無し\"\n",
    "proc1 = proc{|x=2, y=3| x + y}\n",
    "\n",
    "def func(z)\n",
    "  z + yield\n",
    "end\n",
    "  \n",
    "puts func(1,&proc1)\n",
    "puts proc1.arity\n",
    "puts\n",
    "\n",
    "puts \"引数有り\"\n",
    "proc2 = proc{|x=2, y| y=3; x + y}\n",
    "\n",
    "def func(z)\n",
    "  z + yield\n",
    "end\n",
    "  \n",
    "puts func(1,&proc2)\n",
    "puts proc2.arity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 200,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "以下理屈はまだわかってない。。\n",
      "\n",
      "引数無し\n",
      "6\n",
      "-1\n",
      "\n",
      "可変長、引数有り\n",
      "6\n",
      "\n",
      "引数有り。あるのに何故かエラー\n",
      "wrong number of arguments (given 0, expected 1..2)\n",
      "-2\n",
      "\n"
     ]
    }
   ],
   "source": [
    "puts \"以下理屈はまだわかってない。。\"\n",
    "puts\n",
    "\n",
    "puts \"引数無し\"\n",
    "lmd1 = lambda{|x=2, y=3|  x + y}\n",
    "\n",
    "def func(z)\n",
    "  z + yield\n",
    "end\n",
    "  \n",
    "puts func(1,&lmd1)\n",
    "puts lmd1.arity\n",
    "puts\n",
    "\n",
    "puts \"可変長、引数有り\"\n",
    "lmd2 = lambda{|x=2, *y| y=3; x + y}\n",
    "#lmd2 = lambda{|x=2, *y| y = 3;puts x; puts y}\n",
    "\n",
    "def func(z)\n",
    "  z + yield\n",
    "end\n",
    "\n",
    "puts func(1,&lmd2)\n",
    "\n",
    "# puts lmd2.arity\n",
    "puts\n",
    "\n",
    "\n",
    "puts \"引数有り。あるのに何故かエラー\"\n",
    "#lmd3 = lambda{|x=2, y| y=3; x + y}\n",
    "lmd3 = lambda{|x=2, y| puts x; puts y}\n",
    "\n",
    "def func(z)\n",
    "  z + yield\n",
    "end\n",
    "\n",
    "begin\n",
    "  puts func(1,&lmd3)\n",
    "rescue ArgumentError => ex\n",
    "  puts ex\n",
    "end\n",
    "\n",
    "puts lmd3.arity\n",
    "puts"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 199,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2\n",
      "3\n",
      "\n",
      "-2\n",
      "11\n",
      "3\n",
      "wrong number of arguments (given 3, expected 1..2)\n",
      "\n",
      "*yの空配列を整数2で上書きしてるだけ\n",
      "-2\n",
      "[]\n",
      "3\n",
      "\n",
      "xに1, *yに[[1,2]]が入る\n",
      "-2\n",
      "1\n",
      "[[1, 2]]\n",
      "\n",
      "\n",
      "-2\n",
      "[[\"a\", \"b\"], [\"a\", \"b\"], [\"a\", \"b\"]]\n",
      "\n",
      "xに3, *yに[4, 5, 6, 7]が入る\n",
      "-2\n",
      "3\n",
      "[4, 5, 6, 7]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "lmd1 = lambda{|x, y| x + y}\n",
    "puts lmd1.arity\n",
    "puts lmd1.call(1,2)\n",
    "puts\n",
    "\n",
    "lmd2 = lambda{|x=10, y| x + y}\n",
    "puts lmd2.arity\n",
    "puts lmd2.call(1)\n",
    "puts lmd2.call(1,2)\n",
    "begin\n",
    "  puts lmd2.call(1,2,3)\n",
    "rescue ArgumentError => ex\n",
    "  puts ex\n",
    "end\n",
    "puts\n",
    "\n",
    "puts \"*yの空配列を整数2で上書きしてるだけ\"\n",
    "lmd3 = lambda{|x, *y| puts y; y=2; x + y}\n",
    "puts lmd3.arity\n",
    "puts lmd3.call(1)\n",
    "puts\n",
    "\n",
    "puts \"xに1, *yに[[1,2]]が入る\"\n",
    "lmd4 = lambda{|x, *y| puts x;  puts y}\n",
    "puts lmd4.arity\n",
    "puts lmd4.call(1, [1,2])\n",
    "puts\n",
    "\n",
    "lmd5 = lambda{|x, *y| y * x}\n",
    "puts lmd5.arity\n",
    "puts lmd5.call(3, [\"a\",\"b\"])\n",
    "puts\n",
    "\n",
    "puts \"xに3, *yに[4, 5, 6, 7]が入る\"\n",
    "lmd6 = lambda{|x, *y| puts x; puts y}\n",
    "puts lmd6.arity\n",
    "puts lmd6.call(3, 4, 5, 6, 7)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 201,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2\n",
      "3\n",
      "\n",
      "1\n",
      "11\n",
      "3\n",
      "3\n",
      "\n",
      "-2\n",
      "3\n",
      "\n",
      "-2\n",
      "[[\"a\", \"b\"], [\"a\", \"b\"], [\"a\", \"b\"]]\n",
      "[\"a\", \"b\", \"a\", \"b\", \"a\", \"b\"]\n"
     ]
    }
   ],
   "source": [
    "proc1 = proc{|x, y| x + y}\n",
    "puts proc1.arity\n",
    "puts proc1.call(1,2)\n",
    "puts\n",
    "\n",
    "proc2 = proc{|x=10, y| x + y}\n",
    "puts proc2.arity\n",
    "puts proc2.call(1)\n",
    "puts proc2.call(1,2)\n",
    "puts proc2.call(1,2,3,4,5,6,7,8,9)\n",
    "puts\n",
    "\n",
    "proc3 = proc{|x, *y| y=2; x + y}\n",
    "puts proc3.arity\n",
    "puts proc3.call(1)\n",
    "puts\n",
    "\n",
    "proc4 = proc{|x, *y| y * x}\n",
    "puts proc4.arity\n",
    "puts proc4.call(3, [\"a\",\"b\"])\n",
    "puts proc4.call(3, \"a\", \"b\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## ローカル変数の値などは実行時の状態に応じて変化する\n",
    "\n",
    "* オブジェクト生成時のコンテキストを保持している"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "70\n",
      "\n",
      "100\n",
      "\n"
     ]
    }
   ],
   "source": [
    "i = 30\n",
    "j = 40\n",
    "\n",
    "f = Proc.new{puts i + j}\n",
    "puts f.call\n",
    "\n",
    "i = 60\n",
    "\n",
    "puts f.call"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## ブロック付きメソッドの引数として利用する"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "1\n",
      "2\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f = Proc.new{|i| puts i}\n",
    "3.times(&f)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## 手続きオブジェクトの中での処理の中断\n",
    "\n",
    "* メソッド\n",
    "    * next\n",
    "        * 処理を中断する"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 202,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\"next\""
      ]
     },
     "execution_count": 202,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f = Proc.new { next \"next\"; \"last\"}\n",
    "f.call\n",
    "### トップレベルのメソッド外で実行しているので引数の\"next\"を返して終了"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 216,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "トップレベルのメソッドの外でreturnをするとLocalJumpErrorになる\n",
      "unexpected return\n",
      "\n",
      "nextは次の処理に進む\n",
      "func1\n",
      "hoge\n",
      "hoge\n",
      "fuga\n",
      "nil\n",
      "\n",
      "func2\n",
      "hoge\n",
      "fuga\n",
      "nil\n",
      "\n",
      "func3\n",
      "hoge\n",
      "\n"
     ]
    }
   ],
   "source": [
    "puts \"トップレベルのメソッドの外でreturnをするとLocalJumpErrorになる\"\n",
    "f = Proc.new { return \"next\"; \"last\"}\n",
    "begin\n",
    "  f.call\n",
    "rescue LocalJumpError => ex\n",
    "  puts ex\n",
    "end\n",
    "puts\n",
    "\n",
    "puts \"nextは次の処理に進む\"\n",
    "def func1\n",
    "  ary=[1,2,3]\n",
    "  ary.each{|i| next i if i == 2; puts \"hoge\"}\n",
    "  puts \"fuga\"\n",
    "end\n",
    "\n",
    "puts \"func1\"\n",
    "p func1\n",
    "puts\n",
    "\n",
    "def func2\n",
    "  ary=[1,2,3]\n",
    "  ary.each{|i| break i if i == 2; puts \"hoge\"}\n",
    "  puts \"fuga\"\n",
    "end\n",
    "\n",
    "puts \"func2\"\n",
    "p func2\n",
    "puts\n",
    "\n",
    "def func3\n",
    "  ary=[1,2,3]\n",
    "  ary.each{|i| return i if i == 2; puts \"hoge\"}\n",
    "  puts \"fuga\"\n",
    "end\n",
    "\n",
    "puts \"func3\"\n",
    "func3\n",
    "puts"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 236,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2, 3]\n",
      "\n",
      "100\n",
      "\n",
      "メソッドの外で実行\n",
      "1\n",
      "3\n",
      "[1, 2, 3]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[1, 2, 3]"
      ]
     },
     "execution_count": 236,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def func\n",
    "  ary=[1,2,3]\n",
    "  ary.each{|i| next i if i == 3}\n",
    "end\n",
    "p func\n",
    "puts\n",
    "\n",
    "def func\n",
    "  ary=[1,2,3]\n",
    "  ary.each{|i| next i if i == 3}\n",
    "  100\n",
    "end\n",
    "p func\n",
    "puts\n",
    "\n",
    "puts \"メソッドの外で実行\"\n",
    "ary=[1,2,3]\n",
    "p ary.each{|i| next i if i == 2; puts i}\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 237,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "breakの後putsでfugaを表示させると戻り値はnil\n",
      "hoge\n",
      "fuga\n",
      "nil\n",
      "\n",
      "breakで処理が終了すると、戻り値はそのときのiの値\n",
      "hoge\n",
      "2\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 237,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "puts \"breakの後putsでfugaを表示させると戻り値はnil\"\n",
    "def func\n",
    "  ary=[1,2,3]\n",
    "  ary.each{|i| break i if i == 2; puts \"hoge\"}\n",
    "  puts \"fuga\"\n",
    "end\n",
    "p func\n",
    "puts\n",
    "\n",
    "puts \"breakで処理が終了すると、戻り値はそのときのiの値\"\n",
    "def func\n",
    "  ary=[1,2,3]\n",
    "  ary.each{|i| break i if i == 2; puts \"hoge\"}\n",
    "end\n",
    "p func"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## Procクラス以外の手続きオブジェクト\n",
    "\n",
    "* Kernelモジュールのlambdaメソッド\n",
    "    * 引数の数が異なるとArgumentErrorとなる\n",
    "        * Proc.newは引数への多重代入となりエラーにはならない\n",
    "* Kernelモジュールのprocメソッド\n",
    "    * Proc.newと同じ？\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Proc.new\n",
      "1\n",
      "2\n",
      "nil\n",
      "[1, 2, nil]\n",
      "1\n",
      "2\n",
      "3\n",
      "[1, 2, 3]\n",
      "\n",
      "lambda\n",
      "wrong number of arguments (given 2, expected 3)\n",
      "1\n",
      "2\n",
      "3\n",
      "[1, 2, 3]\n",
      "wrong number of arguments (given 4, expected 3)\n",
      "\n",
      "proc\n",
      "1\n",
      "2\n",
      "nil\n",
      "[1, 2, nil]\n",
      "1\n",
      "2\n",
      "3\n",
      "[1, 2, 3]\n",
      "1\n",
      "2\n",
      "3\n",
      "[1, 2, 3]\n"
     ]
    }
   ],
   "source": [
    "puts \"Proc.new\"\n",
    "f = Proc.new{|a,b,c| p a, b, c}\n",
    "puts f.call(1,2)\n",
    "puts f.call(1,2,3,4)\n",
    "puts\n",
    "\n",
    "puts \"lambda\"\n",
    "g = lambda {|a,b,c| p a, b, c}\n",
    "begin\n",
    "  puts g.call(1,2)      #Error\n",
    "rescue ArgumentError => e\n",
    "  puts e\n",
    "end\n",
    "\n",
    "puts g.call(1,2,3)\n",
    "\n",
    "begin\n",
    "  puts g.call(1,2,3,4)      #Error\n",
    "rescue ArgumentError => e\n",
    "  puts e\n",
    "end\n",
    "puts\n",
    "\n",
    "puts \"proc\"\n",
    "h = proc {|a,b,c| p a, b, c}\n",
    "puts h.call(1,2)\n",
    "puts h.call(1,2,3)\n",
    "puts h.call(1,2,3,4)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## 手続きオブジェクト中でのジャンプ構文\n",
    "\n",
    "* メソッド\n",
    "    * break\n",
    "        * Proc.new : LocalJumpError\n",
    "        * proc : LocalJumpError\n",
    "        * lambda : ループ(オブジェクト)を抜ける\n",
    "    * return\n",
    "        * Proc.new : LocalJumpError\n",
    "        * proc : LocalJumpError\n",
    "        * lambda : メソッドを抜ける"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "break\n",
      "\n",
      "Proc.new\n",
      "1\n",
      "break from proc-closure\n",
      "\n",
      "proc\n",
      "2\n",
      "break from proc-closure\n",
      "\n",
      "lambda\n",
      "3\n"
     ]
    }
   ],
   "source": [
    "puts \"break\"\n",
    "puts\n",
    "\n",
    "puts \"Proc.new\"\n",
    "f = Proc.new{|a| p a; break; p a}\n",
    "begin\n",
    "  f.call(1)\n",
    "rescue LocalJumpError => e\n",
    "  puts e\n",
    "end\n",
    "puts\n",
    "\n",
    "puts \"proc\"\n",
    "h = proc {|c| p c; break; p c}\n",
    "begin\n",
    "  h.call(2)\n",
    "rescue LocalJumpError => e\n",
    "  puts e\n",
    "end\n",
    "puts\n",
    "  \n",
    "puts \"lambda\"\n",
    "g = lambda {|b| p b; break; p b}\n",
    "g.call(3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "return\n",
      "\n",
      "Proc.new\n",
      "1\n",
      "unexpected return\n",
      "\n",
      "proc\n",
      "2\n",
      "unexpected return\n",
      "\n",
      "lambda\n",
      "3\n"
     ]
    }
   ],
   "source": [
    "puts \"return\"\n",
    "puts\n",
    "\n",
    "puts \"Proc.new\"\n",
    "f = Proc.new{|a| p a; return; p a}\n",
    "begin\n",
    "  f.call(1)\n",
    "rescue LocalJumpError => e\n",
    "  puts e\n",
    "end\n",
    "puts\n",
    "\n",
    "puts \"proc\"\n",
    "h = proc {|c| p c; return; p c}\n",
    "begin\n",
    "  h.call(2)\n",
    "rescue LocalJumpError => e\n",
    "  puts e\n",
    "end\n",
    "puts\n",
    "  \n",
    "puts \"lambda\"\n",
    "g = lambda {|b| p b; return; p b}\n",
    "g.call(3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "nextは以降は実行せず次のループを開始\n",
      "----\n",
      "1\n",
      "2\n",
      "4\n",
      "5\n",
      "end\n",
      "breakはループを抜ける\n",
      "----\n",
      "1\n",
      "2\n",
      "end\n",
      "returnはメソッドを抜ける\n",
      "----\n",
      "1\n",
      "2\n"
     ]
    }
   ],
   "source": [
    "### まとめ\n",
    "\n",
    "def block_next\n",
    "  puts '----'\n",
    "  (1..5).each do |i|\n",
    "    next if i % 3 == 0\n",
    "    puts i\n",
    "  end\n",
    "  puts 'end'\n",
    "end\n",
    "\n",
    "def block_break\n",
    "  puts '----'\n",
    "  (1..5).each do |i|\n",
    "    break if i % 3 == 0\n",
    "    puts i\n",
    "  end\n",
    "  puts 'end'\n",
    "end\n",
    "\n",
    "def block_return\n",
    "  puts '----'\n",
    "  (1..5).each do |i|\n",
    "    return if i % 3 == 0\n",
    "    puts i\n",
    "  end\n",
    "  puts 'end'\n",
    "end\n",
    "\n",
    "puts \"nextは以降は実行せず次のループを開始\"\n",
    "block_next\n",
    "puts \"breakはループを抜ける\"\n",
    "block_break\n",
    "puts \"returnはメソッドを抜ける\"\n",
    "block_return"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Ruby 2.3.1",
   "language": "ruby",
   "name": "ruby"
  },
  "language_info": {
   "file_extension": ".rb",
   "mimetype": "application/x-ruby",
   "name": "ruby",
   "version": "2.3.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
